<?php

abstract class Jf_View_Abstract implements Jf_View_Interface {

    protected $_tpl_vars = array();

    protected $_tpl_dir = '';

    protected $_options = array();

    public function assign ($name, $value = null) {
        if (is_string ($name)) {
            $this -> _tpl_vars[$name] = $value;
        } elseif (is_array ($name)) {
            foreach ($name as $key => $val) {
                $this -> _tpl_vars[$key] = $val;
            }
        } else {
            throw new Jf_Exception ('assign() expects a string or array, received ' . gettype ($name));
        }
        return $this;
    }

    public function assignRef ($name, &$value) {
        if (is_string ($name)) {
            $this -> _tpl_vars[$name] = $value;
        } else {
            throw new Jf_Exception ('assign() expects a string, received ' . gettype ($name));
        }
        return $this;
    }

    public function setScriptPath ($templateDir) {
        if (is_string ($templateDir) && Jf_Global::isAbsolutePath ($templateDir)) {
            $this -> _tpl_dir = $templateDir;
        }
        return $this;
    }

    public function getScriptPath () {
        return $this -> _tpl_dir;
    }

    public function clear ($name = '') {
        if ($name != '') {
            if (isset ($this -> _tpl_vars[$name])) {
                unset ($this -> _tpl_vars[$name]);
            }
        } else {
            // clear all variables
            $this -> _tpl_vars = array();
        }
    }

    public function display ($tpl, $tplVars = array()) {
        if ( ! is_string ($tpl) || $tpl == null) {
            return false;
        }
        $template = $this -> _script ($tpl);
        echo $this -> _run ($template, $tplVars);
        return true;
    }

    public function evaluate ($tpl_content, $vars = array()) {
        if ( ! is_string ($tpl_content) || $tpl_content == null) {
            return false;
        }
        return $this -> _run ($tpl_content, $vars, true);
    }

    public function get ($name) {
        if ($name) {
            if (isset ($this -> _tpl_vars[$name])) {
                return $this -> _tpl_vars[$name];
            }
        } else {
            return $this -> _tpl_vars;
        }
        return null;
    }

    public function __get ($name) {
        return $this -> get ($name);
    }

    public function __isset ($name) {
        return isset ($this -> _tpl_vars[$name]);
    }

    public function __set ($name, $value) {
        return $this -> assign ($name, $value);
    }

    public function __unset ($name) {
        if (isset ($this -> _tpl_vars[$name])) {
            unset ($this -> _tpl_vars[$name]);
        }
    }

    public function render ($tpl, $tplVars = array()) {
        if ( ! is_string ($tpl) || $tpl == null) {
            return false;
        }
        if ($tplVars) {
            $this -> _tpl_vars = array_merge ($tplVars, $this -> _tpl_vars);
        }
        $file = $this -> _script ($tpl);
        return $this -> _run ($file);
    }

    protected function _script ($name) {
        if (preg_match ('#\.\.[\\\/]#', $name)) {
            throw new Jf_Exception ('Requested scripts may not include parent ' . 'directory traversal ("../", "..\\" notation)');
        }
        if ($this -> _tpl_dir == '') {
            throw new Jf_Exception ('Could not determine the view script path, ' . 'you should call Jf_View_Simple::setScriptPath to specific it');
        }
        if (Jf_Global::isAbsolutePath ($name) && is_readable ($name)) {
            return $name;
        } else 
            if (is_readable ($this -> _tpl_dir . DIRECTORY_SEPARATOR . $name)) {
                return $this -> _tpl_dir . DIRECTORY_SEPARATOR . $name;
            }
        throw new Jf_Exception ("Unable to find template " . $this -> _tpl_dir . DIRECTORY_SEPARATOR . $name);
    }

    protected function _run ($template, $useEval = false) {
        ob_start ();
        if ($useEval == true) {
            eval ('?>' . $template . '<?');
        } else {
            include ($template);
        }
        $content = ob_get_clean ();
        return $content;
    }

}
